package com.bor.gb.rest.handlers;

import com.bor.gb.core.exception.AppException;
import com.bor.gb.core.exception.GuideIsNotValidException;
import com.bor.gb.core.services.GooglePlaceService;
import com.bor.gb.db.domain.Guide;
import com.bor.gb.db.domain.PlaceNote;
import com.bor.gb.db.services.GuideService;
import com.bor.gb.rest.security.CurrentUser;
import com.bor.gb.rest.util.EntityConverter;
import com.bor.gb.rest.util.Response;
import com.bor.gb.rest.util.ResponseUtils;
import com.bor.gb.rest.model.GuideRequest;
import com.bor.gb.rest.model.GuideResponse;
import com.bor.gb.rest.model.PlaceNoteRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by bor on 11/6/14.
 */
@RestController
@RequestMapping("/v01/guide")
public class GuideRestController {
    private static final Log log = LogFactory.getLog(GuideRestController.class);
    @Autowired
    private GuideService guideService;

    @Autowired
    private GooglePlaceService placeService;

    @Autowired
    private EntityConverter converter;

    @RequestMapping(method = RequestMethod.PUT, value = "/new")
    @ResponseBody
    public ResponseEntity newGuide(@Valid @RequestBody GuideRequest guide) {
        try {
            // TODO move to streams
            Set<PlaceNote> notes = new HashSet<>();

            Set<PlaceNoteRequest> entries = guide.getEntries();
            if (entries == null || entries.isEmpty()) {
                throw new GuideIsNotValidException("Guide should has at least one entry");
            }
            entries.forEach(placeNoteRequest -> {
                PlaceNote placeNote = new PlaceNote();
                placeNote.setTitle(placeNoteRequest.getTitle());
                placeNote.setContent(placeNoteRequest.getContent());
                notes.add(placeNote);
            });

            guideService.createGuide(guide.getName(), CurrentUser.getUserId(), guide.getPlaceId(), notes, guide.getDescription());
            return new ResponseEntity("ok", HttpStatus.OK);
        } catch (AppException e) {

            return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
        }
    }

    @RequestMapping(method = RequestMethod.GET, value = "/search")
    public
    @ResponseBody
    ResponseEntity search(@RequestParam(value = "place_id", required = true) String id) {
        try {
            List<GuideResponse> guideResponses = converter.guidesToGuideResponses(guideService.getGuides(id));

            return new ResponseEntity(guideResponses, HttpStatus.OK);

        } catch (AppException e) {
            return new Response.Error(e.getMessage(), HttpStatus.OK);
        } catch (Exception e) {
            log.error("Error occurred during search request processing", e);
            return new Response.Error(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @RequestMapping(method = RequestMethod.POST, value = "/plus")
    public
    @ResponseBody
    ResponseEntity plus(@RequestParam(value = "guide_id") String guideId, @RequestParam(value = "status") boolean status) {
        Guide guide = guideService.plus(guideId, CurrentUser.getUserId(), status);
        log.info(guide);
        return new ResponseEntity(ResponseUtils.guideVotesToJson(guide), HttpStatus.OK);
    }


    @RequestMapping(method = RequestMethod.POST, value = "/minus")
    public
    @ResponseBody
    ResponseEntity minus(@RequestParam(value = "guide_id") String guideId, @RequestParam(value = "status") boolean like) {
        Guide guide = guideService.minus(guideId, CurrentUser.getUserId(), like);
        return new ResponseEntity(ResponseUtils.guideVotesToJson(guide), HttpStatus.OK);
    }

    @ExceptionHandler(AppException.class)
    @ResponseBody
    ResponseEntity handleApplicationException(HttpServletRequest req, Exception ex) {
        log.error(ex);
        return new Response.Error(ex.getMessage(), HttpStatus.OK);
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    ResponseEntity handleOthers(HttpServletRequest req, Exception ex) {
        log.fatal("Unexpected Server error" , ex);
        return new Response.Error(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
